# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

load("//tools/bzl:genrule2.bzl", "genrule2")
load("//tools/bzl:java.bzl", "java_library2")

jar_filetype = [".jar"]

BROWSERS = [
    "chrome",
    "firefox",
    "gecko1_8",
    "safari",
    "msie",
    "ie8",
    "ie9",
    "ie10",
    "edge",
]

ALIASES = {
    "chrome": "safari",
    "edge": "gecko1_8",
    "firefox": "gecko1_8",
    "msie": "ie10",
}

MODULE = "com.google.gerrit.GerritGwtUI"

GWT_COMPILER = "com.google.gwt.dev.Compiler"

GWT_JVM_ARGS = ["-Xmx512m"]

GWT_COMPILER_ARGS = [
    "-XdisableClassMetadata",
]

GWT_COMPILER_ARGS_RELEASE_MODE = GWT_COMPILER_ARGS + [
    "-XdisableCastChecking",
]

GWT_PLUGIN_DEPS_NEVERLINK = [
    "//gerrit-plugin-gwtui:gwtui-api-lib-neverlink",
    "//lib/gwt:user-neverlink",
]

GWT_PLUGIN_DEPS = [
    "//gerrit-plugin-gwtui:gwtui-api-lib",
]

GWT_TRANSITIVE_DEPS = [
    "//lib:jsr305",
    "//lib/gwt:ant",
    "//lib/gwt:colt",
    "//lib/gwt:javax-validation",
    "//lib/gwt:javax-validation_src",
    "//lib/gwt:jsinterop-annotations",
    "//lib/gwt:jsinterop-annotations_src",
    "//lib/gwt:tapestry",
    "//lib/gwt:w3c-css-sac",
    "//lib/ow2:ow2-asm",
    "//lib/ow2:ow2-asm-analysis",
    "//lib/ow2:ow2-asm-commons",
    "//lib/ow2:ow2-asm-tree",
    "//lib/ow2:ow2-asm-util",
]

DEPS = GWT_TRANSITIVE_DEPS + [
    "//java/com/google/gwtexpui/css",
    "//lib:gwtjsonrpc",
    "//lib/gwt:dev",
    "//lib/jgit/org.eclipse.jgit:jgit-source",
]

USER_AGENT_XML = """<module rename-to='gerrit_ui'>
<inherits name='%s'/>
<set-property name='user.agent' value='%s'/>
<set-property name='locale' value='default'/>
</module>
"""

def gwt_module(gwt_xml = None, resources = [], srcs = [], **kwargs):
    if gwt_xml:
        resources = resources + [gwt_xml]

    java_library2(
        srcs = srcs,
        resources = resources,
        **kwargs
    )

def _gwt_user_agent_module(ctx):
    """Generate user agent specific GWT module."""
    if not ctx.attr.user_agent:
        return None

    ua = ctx.attr.user_agent
    impl = ua
    if ua in ALIASES:
        impl = ALIASES[ua]

    # intermediate artifact: user agent speific GWT xml file
    gwt_user_agent_xml = ctx.actions.declare_file(ctx.label.name + "_gwt.xml")
    ctx.actions.write(
        output = gwt_user_agent_xml,
        content = USER_AGENT_XML % (MODULE, impl),
    )

    # intermediate artifact: user agent specific zip with GWT module
    gwt_user_agent_zip = ctx.actions.declare_file(ctx.label.name + "_gwt.zip")
    gwt = "%s_%s.gwt.xml" % (MODULE.replace(".", "/"), ua)
    dir = gwt_user_agent_zip.path + ".dir"
    cmd = " && ".join([
        "p=$PWD",
        "mkdir -p %s" % dir,
        "cd %s" % dir,
        "mkdir -p $(dirname %s)" % gwt,
        "cp $p/%s %s" % (gwt_user_agent_xml.path, gwt),
        "$p/%s cC $p/%s $(find . | sed 's|^./||')" % (ctx.executable._zip.path, gwt_user_agent_zip.path),
    ])
    ctx.actions.run_shell(
        inputs = [gwt_user_agent_xml] + ctx.files._zip,
        outputs = [gwt_user_agent_zip],
        command = cmd,
        mnemonic = "GenerateUserAgentGWTModule",
    )

    return struct(
        zip = gwt_user_agent_zip,
        module = MODULE + "_" + ua,
    )

def _gwt_binary_impl(ctx):
    module = ctx.attr.module[0]
    output_zip = ctx.outputs.output
    output_dir = output_zip.path + ".gwt_output"
    deploy_dir = output_zip.path + ".gwt_deploy"

    deps = _get_transitive_closure(ctx)

    paths = []
    for dep in deps:
        paths.append(dep.path)

    gwt_user_agent_modules = []
    ua = _gwt_user_agent_module(ctx)
    if ua:
        paths.append(ua.zip.path)
        gwt_user_agent_modules.append(ua.zip)
        module = ua.module

    cmd = "%s %s -Dgwt.normalizeTimestamps=true -cp %s %s -war %s -deploy %s " % (
        ctx.attr._jdk[java_common.JavaRuntimeInfo].java_executable_exec_path,
        " ".join(ctx.attr.jvm_args),
        ":".join(paths),
        GWT_COMPILER,
        output_dir,
        deploy_dir,
    )

    # TODO(davido): clean up command concatenation
    cmd += " ".join([
        "-style %s" % ctx.attr.style,
        "-optimize %s" % ctx.attr.optimize,
        "-strict",
        " ".join(ctx.attr.compiler_args),
        module + "\n",
        "rm -rf %s/gwt-unitCache\n" % output_dir,
        "root=`pwd`\n",
        "cd %s; $root/%s Cc ../%s $(find .)\n" % (
            output_dir,
            ctx.executable._zip.path,
            output_zip.basename,
        ),
    ])

    ctx.actions.run_shell(
        inputs = list(deps) + gwt_user_agent_modules,
        outputs = [output_zip],
        tools = ctx.files._jdk + ctx.files._zip,
        mnemonic = "GwtBinary",
        progress_message = "GWT compiling " + output_zip.short_path,
        command = "set -e\n" + cmd,
    )

def _get_transitive_closure(ctx):
    deps = depset()
    for dep in ctx.attr.module_deps:
        deps += dep.java.transitive_runtime_deps
        deps += dep.java.transitive_source_jars
    for dep in ctx.attr.deps:
        if hasattr(dep, "java"):
            deps += dep.java.transitive_runtime_deps
        elif hasattr(dep, "files"):
            deps += dep.files

    return deps

gwt_binary = rule(
    attrs = {
        "compiler_args": attr.string_list(),
        "jvm_args": attr.string_list(),
        "module": attr.string_list(default = [MODULE]),
        "module_deps": attr.label_list(allow_files = jar_filetype),
        "optimize": attr.string(default = "9"),
        "style": attr.string(default = "OBF"),
        "user_agent": attr.string(),
        "deps": attr.label_list(allow_files = jar_filetype),
        "_jdk": attr.label(
            default = Label("@bazel_tools//tools/jdk:current_java_runtime"),
            cfg = "host",
        ),
        "_zip": attr.label(
            default = Label("@bazel_tools//tools/zip:zipper"),
            cfg = "host",
            executable = True,
            allow_single_file = True,
        ),
    },
    outputs = {
        "output": "%{name}.zip",
    },
    implementation = _gwt_binary_impl,
)

def gwt_genrule(suffix = ""):
    dbg = "ui_dbg" + suffix
    opt = "ui_opt" + suffix
    module_dep = ":ui_module" + suffix
    args = GWT_COMPILER_ARGS_RELEASE_MODE if suffix == "_r" else GWT_COMPILER_ARGS

    genrule2(
        name = "ui_optdbg" + suffix,
        srcs = [
            ":" + dbg,
            ":" + opt,
        ],
        cmd = "cd $$TMP;" +
              "unzip -q $$ROOT/$(location :%s);" % dbg +
              "mv" +
              " gerrit_ui/gerrit_ui.nocache.js" +
              " gerrit_ui/dbg_gerrit_ui.nocache.js;" +
              "unzip -qo $$ROOT/$(location :%s);" % opt +
              "mkdir -p $$(dirname $@);" +
              "zip -qrD $$ROOT/$@ .",
        outs = ["ui_optdbg" + suffix + ".zip"],
        visibility = ["//visibility:public"],
    )

    gwt_binary(
        name = opt,
        module = [MODULE],
        module_deps = [module_dep],
        deps = DEPS,
        compiler_args = args,
        jvm_args = GWT_JVM_ARGS,
    )

    gwt_binary(
        name = dbg,
        style = "PRETTY",
        optimize = "0",
        module_deps = [module_dep],
        deps = DEPS,
        compiler_args = GWT_COMPILER_ARGS,
        jvm_args = GWT_JVM_ARGS,
    )

def gen_ui_module(name, suffix = ""):
    gwt_module(
        name = name + suffix,
        srcs = native.glob(["src/main/java/**/*.java"]),
        gwt_xml = "src/main/java/%s.gwt.xml" % MODULE.replace(".", "/"),
        resources = native.glob(
            ["src/main/java/**/*"],
            exclude = ["src/main/java/**/*.java"] +
                      ["src/main/java/%s.gwt.xml" % MODULE.replace(".", "/")],
        ),
        deps = [
            "//gerrit-gwtui-common:diffy_logo",
            "//gerrit-gwtui-common:client",
            "//java/com/google/gwtexpui/css",
            "//lib/codemirror:codemirror" + suffix,
            "//lib/gwt:user",
        ],
        visibility = ["//visibility:public"],
    )

def gwt_user_agent_permutations():
    for ua in BROWSERS:
        gwt_binary(
            name = "ui_%s" % ua,
            user_agent = ua,
            style = "PRETTY",
            optimize = "0",
            module = [MODULE],
            module_deps = [":ui_module"],
            deps = DEPS,
            compiler_args = GWT_COMPILER_ARGS,
            jvm_args = GWT_JVM_ARGS,
        )
